package com.uxsino.simo.collector.connections;

import java.io.IOException;
import java.net.InetAddress;
import java.util.Calendar;
import java.util.Map;

import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.uxsino.commons.utils.IPUtil;
import com.uxsino.simo.connections.AbstractConnection;
import com.uxsino.simo.connections.exception.SimoConnectionException;
import com.uxsino.simo.connections.exception.SimoQueryException;
import com.uxsino.simo.connections.target.FTPTarget;

public class FTPConnection extends AbstractConnection<FTPTarget> {

    private static final Logger logger = LoggerFactory.getLogger(FTPConnection.class);

    private static final int TIMEOUT_MILLISECOND = 600000;

    private FTPClient ftpClient;

    private long connectionTime;

    private long loginTime;

    @Override
    public int connect(FTPTarget target) {
        super.connect(target);
        connected = false;
        ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(TIMEOUT_MILLISECOND);
        try {
            if (IPUtil.isIPv4(target.host)) {
                InetAddress address = IPUtil.convertToInet4Addr(target.host);
                if (address == null) {
                    return 0;
                }
                long startTime = Calendar.getInstance().getTimeInMillis();
                ftpClient.connect(address, target.port);
                connectionTime = Calendar.getInstance().getTimeInMillis() - startTime;
            } else {
                long startTime = Calendar.getInstance().getTimeInMillis();
                ftpClient.connect(target.host, target.port);
                connectionTime = Calendar.getInstance().getTimeInMillis() - startTime;
            }
        } catch (IOException e) {
            logger.error("failed to connect to host", e);
            return 0;
        }
        if (ftpClient.isAvailable()) {
            try {
                long startTime = Calendar.getInstance().getTimeInMillis();
                connected = ftpClient.login(target.getUsername(), target.getPassword(), target.account);
                loginTime = Calendar.getInstance().getTimeInMillis() - startTime;
            } catch (IOException e) {
                logger.error("ftp login failed", e);
                return 0;
            }
        }
        return 1;
    }

    @Override
    public Object execCmd(Object cmdPattern) throws SimoQueryException, SimoConnectionException {
        return getData();
    }

    @Override
    public Object buildCmd(String cmdPattern, Map<String, String> args) throws SimoQueryException {
        return cmdPattern;
    }

    @Override
    public int close() {
        try {
            ftpClient.logout();
        } catch (IOException e) {
            logger.error("error logout", e);
        }
        try {
            ftpClient.disconnect();
        } catch (IOException e) {
            logger.error("error closing ftp connection", e);
        } finally {
            ftpClient = null;
            connected = false;
        }
        super.close();
        return 0;
    }

    private JSONObject getData() {
        JSONObject data = new JSONObject();
        data.put("connection_time", connectionTime);    // in millisecond
        data.put("login_time", loginTime);              // in millisecond
        data.put("IP", ftpClient.getRemoteAddress().toString());
        data.put("port", ftpClient.getRemotePort());
        data.put("buffer_size", ftpClient.getBufferSize()); // in byte
        try {
            data.put("system_type", ftpClient.getSystemType());
        } catch (IOException e) {
            logger.error("error getting system type", e);
        }
        try {
            data.put("status", ftpClient.getStatus());
        } catch (IOException e) {
            logger.error("error getting status", e);
        }
        return data;
    }

}
